package com.amoyt.project.service.admin.impl;

import com.amoyt.project.config.redis.RedisCache;
import com.amoyt.project.config.redis.RedisIdWork;
import com.amoyt.project.constants.IdConstants;
import com.amoyt.project.constants.RedisConstants;
import com.amoyt.project.constants.ResponseConstants;
import com.amoyt.project.domain.bo.LoginUser;
import com.amoyt.project.domain.dto.insert.ProjectApprovalAddDto;
import com.amoyt.project.domain.dto.query.ProjectPageQuery;
import com.amoyt.project.domain.dto.update.ProjectApplyUpdateDto;
import com.amoyt.project.domain.dto.update.ProjectApprovalUpdateDto;
import com.amoyt.project.domain.pojo.ProjectApproval;
import com.amoyt.project.domain.pojo.ProjectApprovalResult;
import com.amoyt.project.domain.res.PageResult;
import com.amoyt.project.domain.res.Result;
import com.amoyt.project.domain.vo.ProjectApprovalDetailVo;
import com.amoyt.project.domain.vo.ProjectApprovalResultVo;
import com.amoyt.project.domain.vo.ProjectLevelVo;
import com.amoyt.project.domain.vo.data.ProjectTrendVo;
import com.amoyt.project.enums.AdminLevelEnum;
import com.amoyt.project.enums.ProjectLevelEnum;
import com.amoyt.project.exception.BusinessException;
import com.amoyt.project.exception.enums.BusinessExceptionEnum;
import com.amoyt.project.mapper.ProjectApprovalMapper;
import com.amoyt.project.mapper.ProjectApprovalResultMapper;
import com.amoyt.project.service.admin.ProjectService;
import com.amoyt.project.utils.ConvertBeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 项目审批主表（存储申请信息） 服务实现类
 * </p>
 *
 * @author AmoyT
 * @since 2025-08-24
 */
@Service
@Slf4j
public class ProjectServiceImpl implements ProjectService {

    @Autowired
    private ProjectApprovalMapper projectApprovalMapper;
    @Autowired
    private ProjectApprovalResultMapper projectApprovalResultMapper;
    @Autowired
    private RedisIdWork redisIdWork;
    @Autowired
    private RedisCache redisCache;

    @Override
    public Result listAll(ProjectPageQuery query) {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String currentRole = loginUser.getAuthorities().stream()
                .findFirst()
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                .orElse("");
        if (currentRole == null){
            //无权限
            throw new BusinessException(BusinessExceptionEnum.PERMISSION_ERROR);
        }

        //下级列表
        List<String> levelList = ProjectLevelEnum.getLowerLevel(currentRole);

        IPage<ProjectApproval> page = new Page<>(query.getPage(), query.getPageSize());
        QueryWrapper<ProjectApproval> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("project_level", levelList)
                .ne("create_by", loginUser.getUser().getUserId())
                .between(query.getStartTime() != null, "create_time", query.getStartTime(), query.getEndTime());
        IPage<ProjectApproval> projectApprovals = projectApprovalMapper.selectPage(page, queryWrapper);

        projectApprovals.getRecords().forEach(projectApproval -> {
            projectApproval.setApplyMoney(projectApproval.getApplyMoney()/100L);
        });

        PageResult pageResult = PageResult.builder()
                .total(projectApprovals.getTotal())
                .records(projectApprovals.getRecords())
                .build();
        return Result.success(pageResult);
    }

    @Override
    public Result listCurrApprovalList(ProjectPageQuery query) {
        //已申请
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        IPage<ProjectApproval> page = new Page<>(query.getPage(), query.getPageSize());
        QueryWrapper<ProjectApproval> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("create_by", loginUser.getUser().getUserId());
        queryWrapper.orderByDesc("apply_time");
        queryWrapper.like(query.getProjectNum() != "", "project_num", query.getProjectNum());
        queryWrapper.like(query.getProjectName() != "", "project_name", query.getProjectName());
        queryWrapper.like(query.getApplyUnit() != "", "apply_unit", query.getApplyUnit());
        queryWrapper.eq(query.getOverallStatus() != "", "overall_status", query.getOverallStatus());
        queryWrapper.between(query.getStartTime() != null && query.getEndTime() != null, "apply_time", query.getStartTime(), query.getEndTime());
//                .eq("overall_status", ProjectLevelEnum.STATUS_PENDING)
//                .eq("current_approval_level", AdminLevelEnum.getLevel(loginUser.getAuthorities().stream().findFirst().get().getAuthority()));

        IPage<ProjectApproval> projectApprovals = projectApprovalMapper.selectPage(page, queryWrapper);

        projectApprovals.getRecords().forEach(projectApproval -> {
            projectApproval.setApplyMoney(projectApproval.getApplyMoney()/100L);
        });

        PageResult pageResult = PageResult.builder()
                .total(projectApprovals.getTotal())
                .records(projectApprovals.getRecords())
                .build();

        return Result.success(pageResult);

    }

    @Override
    public Result listApprovalList(ProjectPageQuery query) {

        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String currentRole = loginUser.getAuthorities().stream()
                .findFirst()
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                .orElse("");

        //需要审批或者待审批的
        IPage<ProjectApproval> page = new Page<>(query.getPage(), query.getPageSize());
        //条件
        QueryWrapper<ProjectApproval> queryWrapper = new QueryWrapper<>();

        //获取申请级别更高，并且不是自己申请的
        List<String> levelList = ProjectLevelEnum.getHigherLevel(currentRole);
        queryWrapper.in("project_level", levelList)
                .ne("create_by", loginUser.getUser().getUserId());

        IPage<ProjectApproval> projectApprovals = projectApprovalMapper.selectPage(page, queryWrapper);

        projectApprovals.getRecords().forEach(projectApproval -> {
            projectApproval.setApplyMoney(projectApproval.getApplyMoney()/100L);
        });

        PageResult pageResult = PageResult.builder()
                .total(projectApprovals.getTotal())
                .records(projectApprovals.getRecords())
                .build();

        return Result.success(pageResult);
    }

    @Override
    @Transactional
    public Result approvalUpdate(ProjectApprovalUpdateDto dto) {

        //获取当前审批级别
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String currentRole = loginUser.getAuthorities().stream()
                .findFirst()
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                .orElse("");

        //查询，防止篡改数据
        ProjectApproval project = projectApprovalMapper.selectById(dto.getProjectId());
        log.info("当前项目：{}", project);
        System.out.println(dto.getApprovalLevel().equals(project.getCurrentApprovalLevel()) + "===" + project.getCurrentApprovalLevel() + "===" + dto.getApprovalLevel());
        if (project == null || !dto.getApprovalLevel().equals(project.getCurrentApprovalLevel())){
            throw new BusinessException(BusinessExceptionEnum.PARAM_ERROR);
        }

        //是不是可以审批 比如prov_admin权限，看到的应该是待审批级别同样为prov_admin的
        log.info("当前用户角色：{},目标", currentRole, project.getCurrentApprovalLevel());
        boolean isOk = ProjectLevelEnum.isCanApproval(currentRole, project.getCurrentApprovalLevel());
        if (!isOk){
            return Result.error(ResponseConstants.STATUS_NOT_ALLOW_APPROVAL);
        }

        //可以审批，看是否最后一层级，然后插入数据
        ProjectApproval newUpdateData = ProjectApproval.builder()
                .projectId(project.getProjectId())
                .build();

        //当前待审批级别和项目级别一致，则说明是最后的了，则修改状态
        boolean isLast = ProjectLevelEnum.isLastLevel(project.getCurrentApprovalLevel(), project.getProjectLevel());
        if (isLast){
            if (dto.getApprovalResult().equals(ProjectLevelEnum.PROJECT_PASS)){
                //通过
                newUpdateData.setOverallStatus(ProjectLevelEnum.STATUS_PASSED);
            }else if (dto.getApprovalResult().equals(ProjectLevelEnum.PROJECT_REJECT)){
                //驳回
                newUpdateData.setOverallStatus(ProjectLevelEnum.STATUS_REJECTED);
            }else {
                throw new BusinessException(BusinessExceptionEnum.PARAM_ERROR);
            }
        }else {
            //审批中，则说明不是最后的了，则修改状态
            newUpdateData.setOverallStatus(ProjectLevelEnum.STATUS_UNDER_APPROVAL);
            String nextLevel = ProjectLevelEnum.nextLevel(currentRole);
            newUpdateData.setCurrentApprovalLevel(nextLevel);
        }
        newUpdateData.setUpdateBy(loginUser.getUser().getUserId());
        newUpdateData.setUpdateTime(LocalDateTime.now());
        projectApprovalMapper.updateById(newUpdateData);

        //插入审批记录
        ProjectApprovalResult approvalResult = ProjectApprovalResult.builder()
                .projectId(project.getProjectId())
                .approverId(loginUser.getUser().getUserId())
                .approvalLevel(currentRole)
                .approverName(loginUser.getUser().getRealName())
                .approvalTime(LocalDateTime.now())
                .approvalResult(dto.getApprovalResult())
                .approvalRemark(dto.getApprovalRemark())
                .createBy(loginUser.getUser().getUserId())
                .createTime(LocalDateTime.now())
                .build();
        projectApprovalResultMapper.insert(approvalResult);

        return Result.success("审批完成",null);
    }

    @Override
    @Transactional
    public Result doApply(ProjectApprovalAddDto dto) {
        ProjectApproval project = ConvertBeanUtils.convert(dto, ProjectApproval.class);

        //主键
        String projectId = IdConstants.PROJECT_ID_PREFIX +redisIdWork.nextId(IdConstants.PROJECT_ID_PREFIX);
        project.setProjectId(projectId);

        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        project.setCreateBy(loginUser.getUser().getUserId());
        project.setUpdateBy(loginUser.getUser().getUserId());
        project.setCreateTime(LocalDateTime.now());
        project.setUpdateTime(LocalDateTime.now());
        project.setOverallStatus(ProjectLevelEnum.STATUS_PENDING);
        project.setApplyMoney(dto.getApplyMoney()*100L);

        //设置待审批的级别 下一级别
        String currentRole = loginUser.getAuthorities().stream()
                .findFirst()
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                .orElse("");
        project.setCurrentApprovalLevel(ProjectLevelEnum.nextLevel(currentRole));

        //设置项目编号
        long threadId = Thread.currentThread().getId();
        //1.获取锁
        boolean tryLock = redisCache.tryLock(RedisConstants.ICR_PROJECT_CODE_LOCK, threadId, RedisConstants.ICR_PROJECT_LOCK_TTL);
        if (!tryLock){
            return Result.error(ResponseConstants.SYSTEM_BUSY);
        }

        // 获取并生成项目编号
        Long projectNumber;
        // 尝试从Redis获取当前编号
        Object cacheObj = redisCache.getCacheObject(RedisConstants.ICR_PROJECT_CODE);

        if (cacheObj == null) {
            // 初始值设置，确保Redis中存在初始值
            projectNumber = 100101001L;
            redisCache.setCacheObject(RedisConstants.ICR_PROJECT_CODE, projectNumber);
        } else {
            // 处理类型转换，兼容可能的Integer或Long类型
            if (cacheObj instanceof Integer) {
                projectNumber = ((Integer) cacheObj).longValue();
            } else if (cacheObj instanceof Long) {
                projectNumber = (Long) cacheObj;
            } else {
                // 处理异常类型，使用默认值
                projectNumber = 100101001L;
                redisCache.setCacheObject(RedisConstants.ICR_PROJECT_CODE, projectNumber);
            }
            // 原子递增并获取新值，确保并发安全
            projectNumber = redisCache.increment(RedisConstants.ICR_PROJECT_CODE);
        }

        //释放
        redisCache.unLock(RedisConstants.ICR_PROJECT_CODE_LOCK, threadId);

        project.setProjectNum(IdConstants.PROJECT_ID_PREFIX + projectNumber);

        projectApprovalMapper.insert(project);

        //删除缓存数据
        redisCache.deleteObject(RedisConstants.CACHE_PROJECT_DATA);
        return Result.success();
    }

    @Override
    public Result updateApply(ProjectApplyUpdateDto dto) {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        //获取主键
        String projectId = dto.getProjectId();
        QueryWrapper<ProjectApproval> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("project_id", projectId);
        queryWrapper.eq("create_by", loginUser.getUser().getUserId());
        ProjectApproval queryApproval = projectApprovalMapper.selectOne(queryWrapper);
        if (queryApproval == null){
            return Result.error(ResponseConstants.DATA_NOT_EXIST);
        }

        if (!queryApproval.getCreateBy().equals(loginUser.getUser().getUserId())){
            return Result.error(ResponseConstants.DATA_TAMPERING_ERROR);
        }

        //判断当前状态
        if(!queryApproval.getOverallStatus().equals(ProjectLevelEnum.STATUS_PENDING)){
            //状态不允许修改
            return Result.error(ResponseConstants.STATUS_NOT_ALLOW_UPDATE);
        }

        //只有待审批过程才可以提交修改
        ProjectApproval project = ConvertBeanUtils.convert(dto, ProjectApproval.class);
        project.setApplyMoney(dto.getApplyMoney()*100L);

        projectApprovalMapper.updateById(project);

        return Result.success();
    }

    @Override
    public Result queryProjectLevel() {
        //肯定不能比自己低啊
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String currentRole = loginUser.getAuthorities().stream()
                .findFirst()
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                .orElse("");

        //不要第一个
        List<ProjectLevelVo> roleList = ProjectLevelEnum.queryProjectLevel(currentRole);

        return Result.success(roleList);
    }

    @Override
    public Result delete(List<String> ids) {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        projectApprovalMapper.deleteList(ids,loginUser.getUser().getUserId());
        return Result.success();
    }

    @Override
    public Result queryProjectDetail(String projectId) {
        //项目+审批详情
        ProjectApproval project = projectApprovalMapper.selectById(projectId);
        List<ProjectApprovalResult> approvalResults = queryApprovalList(projectId,ProjectApprovalResult.STATUS_VALID);

        //排序
        approvalResults.sort(new Comparator<ProjectApprovalResult>() {
            @Override
            public int compare(ProjectApprovalResult o1, ProjectApprovalResult o2) {
                //数字小，在前面
                return o1.getApprovalOrder() - o2.getApprovalOrder();
            }
        });

        ProjectApprovalDetailVo projectApprovalDetailVo = ConvertBeanUtils.convert(project, ProjectApprovalDetailVo.class);
        List<ProjectApprovalResultVo> approvalResultVos = ConvertBeanUtils.convertList(approvalResults, ProjectApprovalResultVo.class);

        projectApprovalDetailVo.setApprovalResults(approvalResultVos);
        projectApprovalDetailVo.setApplyMoney(project.getApplyMoney()/100L);

        return Result.success(projectApprovalDetailVo);
    }

    @Override
    public Result queryProjectApprovalDetail(String projectId) {

        //查询审批过程列表
        List<ProjectApprovalResult> approvalResults = queryApprovalList(projectId,ProjectApprovalResult.STATUS_VALID);

        //对approvalResults排序，按照order字段排序，越小的越在前面
        approvalResults.sort(new Comparator<ProjectApprovalResult>() {
            @Override
            public int compare(ProjectApprovalResult o1, ProjectApprovalResult o2) {
                //数字小，在前面
                return o1.getApprovalOrder() - o2.getApprovalOrder();
            }
        });

        List<ProjectApprovalResultVo> approvalResultVos = ConvertBeanUtils.convertList(approvalResults, ProjectApprovalResultVo.class);


        return Result.success(approvalResultVos);
    }

    /**
     * 封装根据id查询审批列表
     * @param projectId
     * @return
     */
    private List<ProjectApprovalResult> queryApprovalList(String projectId,Integer status) {
        QueryWrapper<ProjectApprovalResult> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("project_id", projectId);
        queryWrapper.eq(status != null, "status", status);

        return projectApprovalResultMapper.selectList(queryWrapper);
    }

    @Override
    public Result queryProjectTrend() {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        // 计算日期范围：今天及前6天，共7天
        LocalDate today = LocalDate.now();
        LocalDate startDate = today.minusDays(6);

        // 关键修正：将结束时间设为当天23:59:59，确保包含整天
        LocalDateTime endDateTime = today.atTime(23, 59, 59);

        // 构建查询条件
        QueryWrapper<ProjectApprovalResult> queryWrapper = Wrappers.query();
        queryWrapper.eq("approver_id", loginUser.getUser().getUserId())
                // 开始时间：startDate的00:00:00（默认）
                .ge("approval_time", startDate.atStartOfDay())
                // 结束时间：today的23:59:59（精确到秒）
                .le("approval_time", endDateTime)
                .select("DATE_FORMAT(approval_time, '%Y-%m-%d') as date, COUNT(*) as count")
                .groupBy("DATE_FORMAT(approval_time, '%Y-%m-%d')")
                .orderByAsc("date");

        // 执行查询并映射到VO
        List<ProjectTrendVo> trendVos = projectApprovalResultMapper.selectMaps(queryWrapper).stream()
                .map(map -> {
                    ProjectTrendVo vo = new ProjectTrendVo();
                    vo.setDate((String) map.get("date"));
                    vo.setCount(Integer.parseInt(map.get("count").toString()));
                    return vo;
                })
                .collect(Collectors.toList());

        // 生成完整的7天日期列表（确保每天都有数据）
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, Integer> countMap = trendVos.stream()
                .collect(Collectors.toMap(
                        ProjectTrendVo::getDate,
                        ProjectTrendVo::getCount,
                        (existing, replacement) -> existing
                ));

        List<ProjectTrendVo> resultList = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            LocalDate currentDate = startDate.plusDays(i);
            String dateStr = currentDate.format(formatter);

            ProjectTrendVo vo = new ProjectTrendVo();
            vo.setDate(dateStr);
            vo.setCount(countMap.getOrDefault(dateStr, 0));

            resultList.add(vo);
        }

        return Result.success(resultList);
    }

}
